package org.zoomdev.zoom.server;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.webapp.WebAppContext;
import org.zoomdev.zoom.common.exceptions.ZoomException;
import org.zoomdev.zoom.web.WebService;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import java.util.EnumSet;
import java.util.Map;

public class WebAppServer {

    public static final int DEFAULT_PORT = 8090;

    public static final String DEFAULT_CONTEXT_PATH = "/";

    public static final String DEFAULT_RESOURCE_BASE = "";


    private static final Logger log = LoggerFactory.getLogger(WebAppServer.class);
    private final int port;
    private final String resourceBase;
    private final String contextPath;
    private final Filter filter;
    private WebAppContext webAppContext;
    private Server server;
    private Map<String, String> params;

    public WebAppServer() {
        this(DEFAULT_PORT);
    }

    public WebAppServer(int port) {
        this(port, DEFAULT_CONTEXT_PATH);
    }

    public WebAppServer(int port, String contextPath) {
        this(port, contextPath, DEFAULT_RESOURCE_BASE);
    }

    public WebAppServer(int port, String contextPath, String resourceBase) {
        this(port, contextPath, resourceBase, null);
    }

    public WebAppServer(int port, String contextPath, String resourceBase, Filter filter) {
        this.port = port;
        this.contextPath = contextPath;
        this.resourceBase = resourceBase;
        this.filter = filter;

    }


    public void startup() throws Exception {
        if (server != null) return;
        log.info("Server starting..., contextPath: '{}' Port: {}", contextPath, port);
        QueuedThreadPool threadPool = new QueuedThreadPool();
        threadPool.setMaxThreads(200);
        threadPool.setMinThreads(20);
        threadPool.setIdleTimeout(60000);
        server = new Server(threadPool);

        // 创建连接器
        ServerConnector connector = new ServerConnector(server);
        connector.setPort(port);
        connector.setAcceptQueueSize(1024);     // 连接等待队列
        connector.setIdleTimeout(30000);        // 空闲超时
        connector.setReuseAddress(true);        // 启用端口复用

        server.addConnector(connector);
        server.setHandler(createHandler());
        server.start();
        log.info("Server started, contextPath: '{}' Port: {}", contextPath, port);

    }

    public void join() {
        if (server == null) {
            return;
        }
        try {
            server.join();
        } catch (InterruptedException e) {

        }
    }


    public void restart() {


        try {
            webAppContext.stop();
        } catch (Exception e) {
            throw new ZoomException(e);
        }

        try {
            server.stop();
        } catch (Exception e) {
            throw new ZoomException("停止服务失败", e);
        }

        try {
            webAppContext.start();
        } catch (Exception e) {
            throw new ZoomException(e);
        }


        try {
            server.start();
        } catch (Exception e) {
            throw new ZoomException("启动服务失败", e);
        }
    }


    public void setInitParameters(Map<String, String> data) {
        this.params = data;
    }

    public void shutdown() {
        if (server != null) {
            try {
                server.stop();
            } catch (Exception e) {

            }
            server.destroy();
            server = null;
        }


        if (webAppContext != null) {
            try {
                webAppContext.stop();
            } catch (Exception e) {
                throw new ZoomException(e);
            } finally {
                webAppContext.destroy();
                webAppContext = null;
            }

        }
    }

//    private String getStoreDir() {
//        log.info("Server root path:" + PathUtils.getRootPath());
//        String storeDir = PathUtils.getRootPath() + "session" + contextPath;
//        log.info("Store session to :" + storeDir);
//        if ("\\".equals(File.separator))
//            storeDir = storeDir.replaceAll("/", "\\\\");
//        File file = new File(storeDir);
//        if (!file.exists()) {
//            file.mkdirs();
//        }
//        return storeDir;
//    }
//
//    private void persistSession(WebAppContext webApp) throws IOException {
//        String storeDir = getStoreDir();
//
//        SessionManager sm = webApp.getSessionHandler().getSessionManager();
//        if (sm instanceof HashSessionManager) {
//            ((HashSessionManager) sm).setIdleSavePeriod(1);
//            ((HashSessionManager) sm).setStoreDirectory(new File(storeDir));
//            return;
//        }
//
//        HashSessionManager hsm = new HashSessionManager();
//        hsm.setStoreDirectory(new File(storeDir));
//        hsm.setIdleSavePeriod(1);
//        SessionHandler sh = new SessionHandler();
//        sh.setSessionManager(hsm);
//        webApp.setSessionHandler(sh);
//    }

    public boolean isAlive() {

        return webAppContext.isAvailable();
    }

    protected AbstractHandler createHandler() {
        webAppContext = new WebAppContext();
        webAppContext.setResourceBase(resourceBase);
        webAppContext.setContextPath(contextPath);
        FilterHolder holder;
        if (filter != null) {
            holder = new FilterHolder(filter);
        } else {
            holder = new FilterHolder(WebService.class);
            if (params != null) {
                holder.setInitParameters(params);
            }
        }
        webAppContext.addFilter(holder, "/*", EnumSet.of(DispatcherType.REQUEST));
        webAppContext.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false");
        webAppContext.setInitParameter("org.eclipse.jetty.servlet.Default.useFileMappedBuffer", "false");
        return webAppContext;
    }


}
